package design_principles.singleton_pattern.code;

import java.io.Serializable;


public class SingletonStatic implements Serializable{
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    /**
     * 为了测试，访问修饰符应该是private的
     */
    private SingletonStatic(){
        //优化 ,防止 反射 黑科技 创建类型
        if(LazyHolder.LAZY!=null){
            throw new RuntimeException("singleton can't create one more time");
        }

        System.out.println("SingletonStatic init");
    }
    /**
     * 使用final，禁止重写、重载方法
     * static保证单例的空间共享，变为类的方法
     * @return
     */
    public static final SingletonStatic getInstance(){
        
        return LazyHolder.LAZY;
    }
    /**
     * 利用静态内部类实现延迟加载单例对象
     * tips：内部类想要有静态成员，类必须静态的
     */
    private static class LazyHolder{
        private static final SingletonStatic LAZY;
        /**
         * 利用静态块 打印log
         * 等价于 private static final SingletonStatic singletonStatic=new SingletonStatic();
         * 
         * tips：目前Oracle公司实现的Javac编译器的选择是，如果同时使用final和static来修饰一个
         * 变量（按照习惯，这里称“常量”更贴切），并且这个变量的数据类型是基本类型
         * 或者java.lang.String的话，就将会生成ConstantValue属性来进行初始化；
         * 如果这个变量没有被final修饰，或者并非基本类型及字符串，
         * 则将会选择在<clinit>()方法中进行初始化。
         * 
         * ConstantValue属性：如果类字段的字段属性表中存在ConstantValue属性，那在准备阶段变量值就会被初始化为ConstantValue属性所指定的初始值
         * 
         * init（对象构造器） is the (or one of the) constructor(s) for the instance, and non-static field initialization. 
         * clinit（类构造器） are the static initialization blocks for the class, and static field initialization.
         */
        static{
            LAZY =new SingletonStatic();
            System.out.println("InnerClass static init");
        }
        /**
         * tips：虽然增加readResolve()方法返 回实例解决了单例模式被破坏的问题，
         * 但是实际上实例化了两次，只不 过新创建的对象没有被返回而已。
         */
        private Object readObject(){
            return LazyHolder.LAZY;
        }
    }
}